package cmd

import (
	"fmt"
	"github.com/gin-contrib/pprof"
	"net/http"
	"webmsg/src"
	"webmsg/ui"

	"github.com/gin-contrib/cors"
	"github.com/gin-gonic/gin"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/unrolled/secure"
)

var runCmd = &cobra.Command{
	Use:   "run",
	Short: "launch the server",
	Long:  "launch the server",
	RunE:  run,
}

func init() {
	// 将当前命令设置为根命令的子命令
	rootCmd.AddCommand(runCmd)
}

func run(cmd *cobra.Command, args []string) error {
	logrus.WithFields(logrus.Fields{"method": "run"}).Info("Launching...")
	err := launchServer()
	return err
}

func tlsHandler() gin.HandlerFunc {
	return func(c *gin.Context) {
		secureMiddleware := secure.New(secure.Options{
			SSLRedirect: true,
			SSLHost:     fmt.Sprintf("%s:%d", cfg.Host, cfg.Port),
		})
		err := secureMiddleware.Process(c.Writer, c.Request)

		// If there was an error, do not continue.
		if err != nil {
			return
		}

		c.Next()
	}
}

// 启动服务
func launchServer() error {
	// 启动hub
	hub := src.NewHub()
	go hub.Run()
	var err error

	r := gin.Default()

	// debug模式
	if logrus.GetLevel() >= logrus.DebugLevel {
		logrus.WithFields(logrus.Fields{"method": "launch"}).Info("Enter debug mode")
		// 测试页面
		// r.Static("/demo", "./ui/demo")
		embedUi(r)

		// 跨域中间件
		config := cors.DefaultConfig()
		config.AllowOrigins = []string{"*"}
		config.AllowHeaders = []string{"*"}
		config.ExposeHeaders = []string{"Content-Type"}
		config.AllowCredentials = true
		//config.AllowWebSockets = true
		r.Use(cors.New(config))
	}

	// 处理websocket请求
	r.GET("/", func(c *gin.Context) {
		src.ServeWs(hub, c.Writer, c.Request)
	})
	// 处理后端主动推送
	r.POST("/push", func(c *gin.Context) {
		var msg src.Message
		if err := c.ShouldBindJSON(&msg); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}
		if msg.To == "" || msg.Type == "" || msg.Content == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid args"})
			return
		}
		hub.Push(msg.To, msg.Type, []byte(msg.Content))
		c.JSON(http.StatusOK, gin.H{"msg": "推送成功", "code": 200})
	})

	// 启动服务
	if cfg.Https {
		// golang不支持带密码的ssl key解析，必须生成不带密码的ssl key，
		// 通过以下命令将ssl key的密码去掉，然后使用去掉密码的key即可
		// openssl rsa -in key.pem -out key.unencrypted.pem -passin pass:TYPE_YOUR_PASS
		r.Use(tlsHandler())
		if cfg.Pprof {
			pprof.Register(r)
		}

		err = r.RunTLS(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port), cfg.CertFile, cfg.KeyFile)
		if err != nil {
			return err
		}
		//logrus.WithFields(logrus.Fields{"location": "run", "method": "launchServer"}).Info("Listening at: " + fmt.Sprintf("HTTPS://%s:%d", cfg.Host, cfg.Port))
		return nil
	}

	if cfg.Pprof {
		pprof.Register(r)
	}
	err = r.Run(fmt.Sprintf("%s:%d", cfg.Host, cfg.Port))
	if err != nil {
		return err
	}
	return nil
}

// 打包UI资源
func embedUi(r *gin.Engine) {
	ebdUi := &ui.WebUi{
		Fs:   ui.Dist,
		Path: "demo",
	}
	r.StaticFS("/demo", http.FS(ebdUi))
}
